import {observe} from './index'
import { arrayMethods, observerArray, dependArray } from './array';
import Dep from './dep';
class Observer { // es6类 
    constructor(data){ // data 就是我们刚才定义的vm._data
        // 将用户的数据使用defineProperty重新定义

        this.dep = new Dep(); // 此dep 专门为数组而设定
        // 每个对象 包括数组都有一个 __ob__ 属性 它返回的是当前observer实例
        Object.defineProperty(data, '__ob__',{
            get:()=>this
        });
        if(Array.isArray(data)){ /** 如果是数组 不仅需要观测数组里的成员 还需要对数组的方法进行拦截*/
            data.__proto__ = arrayMethods; //让数组 通过链来查找我们自己编写的原型
            // 当调用数组的方法时 手动通知
            observerArray(data); // 观测数据中的每一项

        }else{
            this.walk(data);
        }
    }
    walk(data){ 
        let keys = Object.keys(data);
        for(let i = 0 ; i < keys.length;i++){
            let key = keys[i]; // 用户传入的key
            let value = data[keys[i]]; // 用户传入的值

            defineReactive(data,key,value);
        }
    }
}
export default Observer

export function defineReactive(data,key,value){ // 定义响应式的数据变化
    // vue 不支持ie8 及 ie8 以下的浏览器
    // 如果value 依旧是一个对象的话 需要深度观察 {school:{name:'zf,age:10}}
    let childOb = observe(value);
    /** 递归观察  {} arr [1,2,3]*/

    const dep = new Dep(); //dep里可以收集依赖 收集的是watcher
    Object.defineProperty(data,key,{
        get(){ // 只要对这个属性进行了取值 操作, 就会将当前的watcher存进去
            if(Dep.target) { // 说明用的是渲染watcher // 在watcher.js 的get 方法中 调用this.getter()时 会进入到此
                /*按语义理解这个应该是依赖的意思,谁的依赖呢？当前属性的依赖→*/dep.depend()/*←这是一个动作,意思是进行依赖搜集*/; // 通过这个方法,他想让dep中可以存watcher, 我还希望让这个watcher中也存放dep, 实现一个多对多的关系, 并且不会重复记忆
                /*
                   每个属性只有一个dep(就是Object.defineProperty上面的那个const dep = new Dep())
                   一个组件对应一个watcher

                   每个dep可以包含多个不同的watcher
                   一个watcher可能也包含多个不同的dep
                */

                if(childOb){ //←只是为了收集数组依赖,虽然对象也会收集,但对象已经收集过了(会被去重处理(addDep)) ... emmm...这个人咋想的 这个childOb判断根本没有必要 一定是有的
                    childOb.dep.depend()
                    dependArray(value);
                }
            }
            return value;
        },

        set(newValue){
            if(newValue === value) return;
            observe(newValue); // 如果你设置的值是一个对象的话 应该在进行监控这个新增的对象
            value = newValue;
            // 通知依赖更新
            dep.notify();
        }
    })
}